package xyz.labmem.app.loading

import atlantafx.base.layout.DeckPane
import javafx.animation.KeyFrame
import javafx.animation.KeyValue
import javafx.animation.Timeline
import javafx.animation.TranslateTransition
import javafx.geometry.Insets
import javafx.geometry.Pos
import javafx.scene.image.ImageView
import javafx.scene.layout.Background
import javafx.scene.layout.StackPane
import javafx.stage.Modality
import javafx.stage.StageStyle
import javafx.util.Duration
import xyz.labmem.app.config.AppConfig
import xyz.labmem.app.config.AppConfig.mouseImage
import xyz.labmem.app.main.MainStage
import xyz.labmem.app.unit.BaseStage
import xyz.labmem.app.util.ScreenType

class LoadingStage(private val parent: BaseStage) : BaseStage() {

    private val stackPane: StackPane
    private val bg1 = ImageView(AppConfig.loadingImage["load-bg1"])
    private val bg2 = ImageView(AppConfig.loadingImage["load-bg2"])
    private val bg3 = ImageView(AppConfig.loadingImage["load-bg3"])
    private val cloud1 = ImageView(AppConfig.loadingImage["load-cloud1"])
    private val cloud2 = ImageView(AppConfig.loadingImage["load-cloud2"])
    private val bgDeck = DeckPane()
    private val imageAction = Timeline()
    private val imageMap = mapOf(0 to bg1, 1 to bg2, 2 to bg3)
    private var imageIndex = 1

    init {
        initOwner(parent)
        initModality(Modality.WINDOW_MODAL)
        initStyle(StageStyle.TRANSPARENT)
        scene.cursor = mouseImage["m3"]
        scene.fill = null
        root.setPrefSize(ScreenType.getWidth(), ScreenType.getHeight())
        root.prefWidthProperty().bind(parent.root.prefWidthProperty())
        root.prefHeightProperty().bind(parent.root.prefHeightProperty())
        root.background = Background.EMPTY
        makeBackGround()
        bgDeck.children.addAll(imageMap.values)
        bgDeck.topNode = imageMap[imageIndex]
        bgDeck.animationDuration = Duration.seconds(.4)
        stackPane = StackPane(
            bgDeck, cloud1, cloud2,
            ImageView(AppConfig.loadingImage["loading"]).apply {
                StackPane.setAlignment(this, Pos.BOTTOM_RIGHT)
                StackPane.setMargin(this, Insets(.0, 60.0, 60.0, .0))
            }
        ).apply {
            prefWidthProperty().bind(root.prefWidthProperty())
            prefHeightProperty().bind(root.prefHeightProperty())
            root.children.add(this)
        }
    }

    private fun makeBackGround() {
        bg1.fitWidthProperty().bind(root.prefWidthProperty())
        bg1.fitHeightProperty().bind(root.prefHeightProperty())
        bg2.fitWidthProperty().bind(root.prefWidthProperty())
        bg2.fitHeightProperty().bind(root.prefHeightProperty())
        bg3.fitWidthProperty().bind(root.prefWidthProperty())
        bg3.fitHeightProperty().bind(root.prefHeightProperty())
        cloud1.fitWidthProperty().bind(root.prefWidthProperty())
        cloud1.fitHeightProperty().bind(root.prefHeightProperty())
        cloud2.fitWidthProperty().bind(root.prefWidthProperty())
        cloud2.fitHeightProperty().bind(root.prefHeightProperty())
        imageAction.cycleCount = Timeline.INDEFINITE

    }

    fun play(run: () -> Unit) {
        y = parent.y
        x = parent.x
        MainStage.setCursor(mouseImage["m3"])
        cloud1.translateY = -parent.root.prefHeight
        cloud2.translateY = -parent.root.prefHeight
        stackPane.translateY = -parent.root.prefHeight
        if (imageAction.keyFrames.isEmpty())
            imageAction.keyFrames.setAll(
                KeyFrame(Duration.seconds(2.5), { _ ->
                    Thread {
                        Thread.sleep(700)
                        Timeline(
                            KeyFrame(
                                Duration.seconds(.6),
                                KeyValue(cloud1.translateYProperty(), 0),
                                KeyValue(cloud2.translateYProperty(), 0)
                            )
                        ).play()
                    }.start()
                    imageIndex = if (imageIndex + 1 >= imageMap.size) 0 else imageIndex + 1
                    if (imageIndex == 2)
                        bgDeck.slideLeft(imageMap[imageIndex])
                    else
                        bgDeck.swipeLeft(imageMap[imageIndex])
                }),

                KeyFrame(Duration.seconds(5.0), { _ ->
                    Thread {
                        Thread.sleep(700)
                        Timeline(
                            KeyFrame(
                                Duration.seconds(.6),
                                KeyValue(cloud1.translateYProperty(), -parent.root.prefHeight),
                                KeyValue(cloud2.translateYProperty(), -parent.root.prefHeight)
                            )
                        ).play()
                    }.start()
                    imageIndex = if (imageIndex + 1 >= imageMap.size) 0 else imageIndex + 1
                    if (imageIndex == 2)
                        bgDeck.slideLeft(imageMap[imageIndex])
                    else
                        bgDeck.swipeLeft(imageMap[imageIndex])
                }),
            )
        show()
        Timeline(
            KeyFrame(Duration.seconds(.2), KeyValue(stackPane.translateYProperty(), 0)),
            KeyFrame(Duration.seconds(.3), { _ -> runThing(run) }),
        ).play()
    }

    private fun runThing(run: () -> Unit) {
        imageAction.play()
        Thread {
            run()
            imageAction.stop()
            val showOut = TranslateTransition(Duration.seconds(.3), stackPane)
            showOut.fromY = 0.0
            showOut.toY = -parent.root.prefHeight
            showOut.setOnFinished {
                MainStage.cursorBack()
                close()
            }
            showOut.play()
            System.gc()
        }.start()
    }
}